home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / System / Infinity Windoid 2.5.1 / WindoidUtil.c < prev    next >
Encoding:
Text File  |  1994-01-16  |  14.5 KB  |  487 lines  |  [TEXT/MPS ]

  1. //******************************************************************************
  2. //
  3. //    FILE:
  4. //        WindoidUtil.c
  5. //
  6. //    WRITTEN BY:
  7. //        Troy Gaul
  8. //        Infinity Systems
  9. //
  10. //        © 1991-94 Infinity Systems
  11. //        All rights reserved.
  12. //
  13. //    DESCRIPTION:
  14. //        This file contains utility routines that the Infinity Windoid
  15. //        WDEF uses in order to get its job done.
  16. //
  17. //    HOW TO CONTACT THE AUTHOR:
  18. //        Send e-mail to: t-gaul@i-link.com
  19. //
  20. //******************************************************************************
  21.  
  22. //******************************************************************************
  23. //    Headers
  24. //------------------------------------------------------------------------------
  25.  
  26. #include "WindoidDefines.h"            // must be included before Apple interfaces
  27.  
  28. #include <Types.h>
  29. #include <Memory.h>
  30. #include <QuickDraw.h>
  31. #include <OSUtils.h>
  32. #include <Windows.h>
  33. #include <Palettes.h>
  34. #include <ToolUtils.h>
  35. #include <GestaltEqu.h>
  36.  
  37. #include "WindoidTypes.h"
  38. #include "WindoidUtil.h"
  39.  
  40. //******************************************************************************
  41. //    Environment-determining Routines                                                                             
  42. //------------------------------------------------------------------------------
  43.     //    These use SysEnvirons by default so we don't have to rely on Gestalt 
  44.     //    being available and so MPW won't include that code in our resource. 
  45.     //    This can be changed by defining USE_GESTALT
  46.  
  47. Boolean 
  48. HasSystem7(void) {
  49. #ifndef USE_GESTALT
  50.     SysEnvRec theWorld;
  51.     
  52.     return (SysEnvirons(1, &theWorld) == noErr 
  53.             && theWorld.systemVersion >= 0x0700);
  54. #else   
  55.     long vers = 0;
  56.     
  57.     return (Gestalt(gestaltSystemVersion, &vers) == noErr 
  58.             && ((vers & 0xFFFF) >= 0x0700));
  59. #endif
  60. }
  61.  
  62. //------------------------------------------------------------------------------
  63.  
  64. Boolean 
  65. HasCQDraw(void) {
  66. #ifndef USE_GESTALT
  67.     SysEnvRec theWorld;
  68.     
  69.     return ((SysEnvirons(1, &theWorld) == noErr) && 
  70.             theWorld.hasColorQD);
  71. #else
  72.      long vers = 0;
  73.     
  74.     return (Gestalt(gestaltQuickdrawVersion, &vers) == noErr 
  75.             && (vers & 0xFF00));
  76. #endif  
  77. }
  78.  
  79. //******************************************************************************
  80. //    SyncPorts
  81. //------------------------------------------------------------------------------
  82.     //    Straight from the pages of _Macintosh Programming Secrets_, Second 
  83.     //    Edition by Scott Knaster and Keith Rollin (page 425). (except that this
  84.     //    version doesn't check Gestalt, it will only be called if CQD is running)
  85.     //    This routines was added to 2.3. It makes sure the drawing environment 
  86.     //    is set correctly if the system has color. This is not needed for the 
  87.     //    code in this WDEF as it is, but if a DoWDrawGIcon handler is implemented, 
  88.     //    this is needed to make sure the drawing environment is set as Apple 
  89.     //    tells us it will be for drawing the gray, xor'ed border.
  90.  
  91. void 
  92. SyncPorts(void) {
  93.     GrafPtr bwPort;
  94.     CGrafPtr colorPort;
  95.     
  96.     GetWMgrPort(&bwPort);
  97.     GetCWMgrPort(&colorPort);
  98.     SetPort((GrafPtr) colorPort);
  99.     
  100.     BlockMove(&bwPort->pnLoc, &colorPort->pnLoc, 10);
  101.     BlockMove(&bwPort->pnVis, &colorPort->pnVis, 14);
  102.     PenPat((ConstPatternParam) &bwPort->pnPat);
  103.     BackPat((ConstPatternParam) &bwPort->bkPat);
  104. }
  105.  
  106. //******************************************************************************
  107. //    OurDeviceLoop
  108. //------------------------------------------------------------------------------
  109. #ifndef SYS7_OR_LATER
  110.  
  111. void 
  112. OurDeviceLoop(RgnHandle drawingRgn, DeviceLoopDrawingProcPtr drawingProc,
  113.               long userData, DeviceLoopFlags flags) {
  114.  
  115.     if (HasSystem7()) {
  116.         DeviceLoop(drawingRgn, drawingProc, userData, flags);
  117.             // this works with or without Color Quickdraw
  118.     } else if (HasCQDraw()) {
  119.         short depth;
  120.         Rect deviceRect;
  121.         GDHandle theDevice;
  122.         RgnHandle saveClip = NewRgn();
  123.         RgnHandle deviceRgn = NewRgn();
  124.         RgnHandle intersectingRgn = NewRgn();
  125.         
  126.         GetClip(saveClip);
  127.         
  128.         //    Get the handle to the first device in the list.
  129.         theDevice = GetDeviceList();
  130.         
  131.         //    Loop through all the devices in the list.
  132.         while (theDevice) {
  133.             // Get the device's gdRect and convert it to local coordinates.
  134.             deviceRect = (**theDevice).gdRect;
  135.             depth = (**(**theDevice).gdPMap).pixelSize;
  136.             
  137.             GlobalToLocal((Point*)&deviceRect.top);
  138.             GlobalToLocal((Point*)&deviceRect.bottom);
  139.             
  140.             //    Check if the app's window rect intersects the device's, and if it
  141.             //    does, set the clip region's rect to the intersection, then DRAW!
  142.             RectRgn(deviceRgn, &deviceRect);
  143.             SectRgn(drawingRgn, deviceRgn, intersectingRgn);
  144.             SectRgn(intersectingRgn, saveClip, intersectingRgn);
  145.             
  146.             if (!EmptyRgn(intersectingRgn)) {
  147.                 SetClip(intersectingRgn);
  148.                 (*drawingProc)(depth, (**theDevice).gdFlags, theDevice, userData);
  149.             }
  150.             
  151.             //    Get the next device in the list.
  152.             theDevice = GetNextDevice(theDevice);
  153.         }
  154.         
  155.         SetClip(saveClip);
  156.         DisposeRgn(saveClip);
  157.         DisposeRgn(deviceRgn);
  158.         DisposeRgn(intersectingRgn);
  159.     } else {
  160.         //    68000 machine, original QuickDraw, punt
  161.         (*drawingProc)(1, 0, nil, userData);
  162.     }
  163. }
  164.  
  165. #endif
  166. //******************************************************************************
  167. //    Color Mixing Routines                                                                     
  168. //------------------------------------------------------------------------------
  169.  
  170. //    This routine will return some defaults in case neither the window's color
  171. //    table nor the System's is long enough to contain the color requested
  172. //    It was provided by Jim Petrick as part of a fix for a bug in version 2.3
  173. //    of the Infinity Windoid. This problem would be seen if a custom WCTB was
  174. //    being used which was not as long as the default System one (or if the
  175. //    System one had been changed to a shorter size). The rest of Jim's fix
  176. //    can be found in GetWctbColor.
  177.  
  178. static void 
  179. UseDefaultColor(short index, RGBColor *theColor) {
  180.     switch (index) {
  181.         case wContentColor:            //     0
  182.         case wTitleBarColor:        //     4
  183.         case wHiliteColorLight:        //     5
  184.         case wTitleBarLight:        //     7
  185.             theColor->red = theColor->green = theColor->blue = 0xFFFF;
  186.             break;
  187.                 
  188.         case wDialogLight:            //     9
  189.         case wTingeLight:            //    11
  190.             theColor->red = theColor->green = 0xCCCC;
  191.             theColor->blue = 0xFFFF;
  192.             break;
  193.         
  194.         case wTingeDark:            //    12
  195.             theColor->red = theColor->green = 0x3333;
  196.             theColor->blue = 0x6666;
  197.             break;
  198.  
  199.         default:
  200.             theColor->red = theColor->green = theColor->blue = 0;
  201.             break;
  202.     }
  203. }
  204.  
  205. //------------------------------------------------------------------------------
  206.  
  207. static void 
  208. GetWctbColor(WindowPeek window, short partCode, RGBColor *theColor) {
  209.     //    Given a partCode, return the RGBColor associated with it. (Using the
  210.     //    default window color table.)
  211.     AuxWinHandle awHndl;
  212.     short count;
  213.     
  214.     //    Get the Color table for the window if it has one.
  215.  
  216.     (void) GetAuxWin((WindowPtr) window, &awHndl); 
  217.     count = (**(WCTabHandle) ((**awHndl).awCTable)).ctSize;
  218.     
  219.  
  220.     //    If the table didn't contain the entry of interest, look to the 
  221.     //    default table.
  222.     
  223.     if (count < partCode) {
  224.         GetAuxWin(nil, &awHndl); 
  225.         count = (**(WCTabHandle) ((**awHndl).awCTable)).ctSize;
  226.     }
  227.             
  228.  
  229.     //    If the entry is there, use it, if not make a best guess at a default value.
  230.  
  231.     if (count < partCode)
  232.         UseDefaultColor(partCode, theColor);
  233.     else
  234.         *theColor = (**(WCTabHandle) ((**awHndl).awCTable)).ctTable[partCode].rgb;
  235. }
  236.  
  237. //------------------------------------------------------------------------------
  238.  
  239. void 
  240. WctbForeColor(WindowPeek window, short partCode) {
  241.     RGBColor theColor;
  242.  
  243.     GetWctbColor(window, partCode, &theColor);
  244.     RGBForeColor(&theColor);
  245. }
  246.  
  247. //------------------------------------------------------------------------------
  248.  
  249. void
  250. WctbBackColor(WindowPeek window, short partCode) {
  251.     RGBColor theColor;
  252.  
  253.     GetWctbColor(window, partCode, &theColor);
  254.     RGBBackColor(&theColor);
  255. }
  256.  
  257. //------------------------------------------------------------------------------
  258. #pragma processor 68020
  259.     // Note: this is okay because this will only be called if we are
  260.     // doing System 7 color, which requires Color Quickdraw, which is only
  261.     // available on systems with 68020's or better. This is done to reduce
  262.     // code size. If it isn't compiled this way, several routines will be
  263.     // added to the code WDEF resource to handle the long integer arithmetic.
  264.  
  265. static void 
  266. MixColor(const RGBColor *light, const RGBColor *dark, 
  267.          short shade, RGBColor *result) {
  268.     shade = 0x0F - shade;
  269.         //    This is necessary because we give shades between light and
  270.         //    dark (0% is light), but for colors, $0000 is black and $FFFF 
  271.         //    is dark.
  272.  
  273.     result->red      = (light->red   - dark->red)   * shade / 15 + dark->red;
  274.     result->green = (light->green - dark->green) * shade / 15 + dark->green;
  275.     result->blue  = (light->blue  - dark->blue)  * shade / 15 + dark->blue;
  276. }
  277.  
  278. #pragma processor 68000
  279. //------------------------------------------------------------------------------
  280.  
  281. static void 
  282. AvgWctbColor(WindowPeek window, short light, short dark, short shade, 
  283.              RGBColor *theColor) {
  284.     // Mix two parts by the given shade, which is actually a value
  285.     // between 0 (0%) and 15 (100%), return the RGBColor.
  286.     RGBColor lightColor;
  287.     RGBColor darkColor;
  288.  
  289.     GetWctbColor(window, light, &lightColor);
  290.     GetWctbColor(window, dark, &darkColor);
  291.     MixColor(&lightColor, &darkColor, shade, theColor);
  292. }
  293.  
  294. //------------------------------------------------------------------------------
  295.  
  296. void 
  297. AvgWctbForeColor(WindowPeek window, short light, short dark, short shade) {
  298.     RGBColor theColor;
  299.     
  300.     AvgWctbColor(window, light, dark, shade, &theColor);
  301.     RGBForeColor(&theColor);
  302. }
  303.  
  304. //------------------------------------------------------------------------------
  305.  
  306. void 
  307. AvgWctbBackColor(WindowPeek window, short light, short dark, short shade) {
  308.     RGBColor theColor;
  309.     
  310.     AvgWctbColor(window, light, dark, shade, &theColor);
  311.     RGBBackColor(&theColor);
  312. }
  313.  
  314. //******************************************************************************
  315. //    CheckDisplay -- Check to see if we are using color title bars
  316. //------------------------------------------------------------------------------
  317.  
  318. static Boolean 
  319. CheckAvailable(WindowPeek window, short light, short dark, 
  320.                short count, short *ramp) {
  321.     // Given a light and dark index value, a count, and and an array of
  322.     // 'percentage' values (0x0 to 0xF, or 0 to 15), see if each of the
  323.     // values in the ramp maps to a different color on the screen. If not,
  324.     // we need to use black-and-white.
  325.     
  326.     RGBColor theColor;
  327.     short i;
  328.     short colorIndex = 0;
  329.     short lastIndex;
  330.     
  331.     for (i = 0 ; i < count ; i++) {
  332.         AvgWctbColor(window, light, dark, ramp[i], &theColor);    
  333.         
  334.         lastIndex = colorIndex;
  335.         colorIndex = Color2Index(&theColor);
  336.         
  337.         if (i > 0 && colorIndex == lastIndex)    // return false if two entries
  338.             return false;                        // have the same index value
  339.     }
  340.     return true;
  341. }
  342.  
  343. //------------------------------------------------------------------------------
  344.  
  345. short 
  346. CheckDisplay(short theDepth, short deviceFlags, 
  347.              GDHandle targetDevice, WindowPeek window) {
  348.     Boolean        inColor;
  349.     short        result;
  350.     RGBColor    testColor;
  351.     GDHandle    saveDevice;
  352.         
  353.     inColor = HasCQDraw() && (deviceFlags & (0x0001 << gdDevType));
  354.     
  355.     result = blackandwhite;                    // assume Black and White
  356.     if (theDepth >= 4) {
  357. #ifndef SYS7_OR_LATER
  358.         if (!HasSystem7()) {
  359.             result = sys6color;                // System 6.0.x Color
  360.         } else {
  361. #endif
  362.             GetWctbColor(window, wTingeLight, &testColor);
  363.             if (testColor.red != 0 || testColor.green != 0 || testColor.blue != 0) 
  364.                 // check for B&W control panel setting, otherwise:
  365.                 result = sys7color;            // System 7.0 Color
  366. #ifndef SYS7_OR_LATER
  367.         }
  368. #endif
  369.     }
  370.     // Note: Since I didn't find another way to see if the user had changed
  371.     // the settings in the Color control panel to the Black-and-white setting,
  372.     // I actually check to see if the rgb components of the light tinge color
  373.     // are non-zero (which seemed to be the case with that setting). 
  374.     
  375.     if (result == sys7color && inColor && theDepth <= 8) {
  376.         short ramp[5];
  377.             // Make sure this array is allocated big enough for the largest ramp.
  378.         
  379.         result = blackandwhite;
  380.         saveDevice = GetGDevice();
  381.         SetGDevice(targetDevice);
  382.  
  383.         ramp[0] = 0x00;
  384.         ramp[1] = 0x07;
  385.         ramp[2] = 0x08;
  386.         ramp[3] = 0x0A;
  387.         ramp[4] = 0x0D;
  388.         if (CheckAvailable(window, wHiliteColorLight, wHiliteColorDark, 5, ramp)) {
  389.             ramp[0] = 0x00;
  390.             ramp[1] = 0x01;
  391.             ramp[2] = 0x04;
  392.             if (CheckAvailable(window, wTitleBarLight, wTitleBarDark, 3, ramp)) {
  393.                 ramp[0] = 0x00;
  394.                 ramp[1] = 0x04;
  395.                 ramp[2] = 0x0F;
  396.                 if (CheckAvailable(window, wTingeLight, wTingeDark, 3, ramp))
  397.                     result = sys7color;
  398.             }
  399.         }
  400.         SetGDevice(saveDevice);
  401.     }
  402.     // This part checks to see if there are 'enough' colors to draw the 
  403.     // title bar in color under System 7. It is supposed to do so in the
  404.     // same way that Apple's system WDEF does. I essentially took the 
  405.     // assembly code that Apple released and tried to make this use the
  406.     // same algorithm.
  407.  
  408.     return result;
  409. }
  410.  
  411. //******************************************************************************
  412. //    Color Utility routines
  413. //------------------------------------------------------------------------------
  414.  
  415. void
  416. ColorsNormal(void) {
  417.     ForeColor(blackColor);
  418.     BackColor(whiteColor);
  419. }
  420.  
  421. //******************************************************************************
  422. //    General Helper Functions
  423. //------------------------------------------------------------------------------
  424.  
  425. void 
  426. FrameBox(const Rect *theRect) {
  427.     Rect tempRect = *theRect;
  428.     
  429.     FrameRect(theRect);
  430.     InsetRect(&tempRect, 1, 1);
  431.     EraseRect(&tempRect);
  432. }
  433.  
  434. //------------------------------------------------------------------------------
  435.  
  436. void
  437. FrameTopLeftShading(Rect theRect) {
  438.     theRect.right--;        // compensate for the way the rectangle hangs
  439.     theRect.bottom--;
  440.  
  441.     MoveTo(theRect.left,  theRect.bottom);            //    •••••
  442.     LineTo(theRect.left,  theRect.top   );            //    •
  443.     LineTo(theRect.right, theRect.top   );            //    •
  444. }
  445.  
  446. //------------------------------------------------------------------------------
  447.  
  448. void
  449. FrameBottomRightShading(Rect theRect) {
  450.     theRect.right--;        // compensate for the way the rectangle hangs
  451.     theRect.bottom--;
  452.  
  453.     MoveTo(theRect.left,  theRect.bottom);            //        •
  454.     LineTo(theRect.right, theRect.bottom);            //        •
  455.     LineTo(theRect.right, theRect.top   );            //    •••••
  456. }
  457.  
  458. //******************************************************************************
  459.  
  460. void
  461. GetGlobalMappingPoint(WindowPeek window, Point *thePoint) {
  462.     //    This routine returns a point that gives the horizontal and vertical
  463.     //  offsets needed to map something into global coordinates.
  464.     GrafPtr savePort;
  465.     
  466.     GetPort(&savePort);
  467.     SetPort((GrafPtr) window);
  468.     
  469.     SetPt(thePoint, 0, 0);
  470.     LocalToGlobal(thePoint);
  471.     
  472.     SetPort(savePort);
  473. }
  474.  
  475. //------------------------------------------------------------------------------
  476.  
  477. void 
  478. GetGlobalContentRect(WindowPeek window, Rect *contentRect) {
  479.     Point mappingPoint;
  480.  
  481.     *contentRect = window->port.portRect;
  482.     GetGlobalMappingPoint(window, &mappingPoint);
  483.     OffsetRect(contentRect, mappingPoint.h, mappingPoint.v);
  484. }
  485.  
  486. //******************************************************************************
  487.